package cn.edu.swu.miniwebsvr.handler;

import cn.edu.swu.miniwebsvr.core.Config;
import cn.edu.swu.miniwebsvr.core.Handler;
import cn.edu.swu.miniwebsvr.core.Parameter;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;

public class DefaultHandler implements Handler {

    // 常见文件类型的MIME类型映射
    private static final Map<String, String> MIME_TYPES = new HashMap<>();

    static {
        // 文本类型
        MIME_TYPES.put("html", "text/html; charset=UTF-8");
        MIME_TYPES.put("htm", "text/html; charset=UTF-8");
        MIME_TYPES.put("css", "text/css; charset=UTF-8");
        MIME_TYPES.put("js", "application/javascript; charset=UTF-8");
        MIME_TYPES.put("json", "application/json; charset=UTF-8");
        MIME_TYPES.put("txt", "text/plain; charset=UTF-8");
        MIME_TYPES.put("xml", "application/xml; charset=UTF-8");

        // 图片类型
        MIME_TYPES.put("jpg", "image/jpeg");
        MIME_TYPES.put("jpeg", "image/jpeg");
        MIME_TYPES.put("png", "image/png");
        MIME_TYPES.put("gif", "image/gif");
        MIME_TYPES.put("svg", "image/svg+xml");
        MIME_TYPES.put("ico", "image/x-icon");
        MIME_TYPES.put("bmp", "image/bmp");
        MIME_TYPES.put("webp", "image/webp");

        // 字体类型
        MIME_TYPES.put("woff", "font/woff");
        MIME_TYPES.put("woff2", "font/woff2");
        MIME_TYPES.put("ttf", "font/ttf");
        MIME_TYPES.put("eot", "application/vnd.ms-fontobject");

        // 应用程序类型
        MIME_TYPES.put("pdf", "application/pdf");
        MIME_TYPES.put("zip", "application/zip");
        MIME_TYPES.put("rar", "application/x-rar-compressed");
        MIME_TYPES.put("7z", "application/x-7z-compressed");
        MIME_TYPES.put("doc", "application/msword");
        MIME_TYPES.put("docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
        MIME_TYPES.put("xls", "application/vnd.ms-excel");
        MIME_TYPES.put("xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        MIME_TYPES.put("ppt", "application/vnd.ms-powerpoint");
        MIME_TYPES.put("pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation");

        // 音频视频类型
        MIME_TYPES.put("mp3", "audio/mpeg");
        MIME_TYPES.put("wav", "audio/wav");
        MIME_TYPES.put("mp4", "video/mp4");
        MIME_TYPES.put("avi", "video/x-msvideo");
        MIME_TYPES.put("mov", "video/quicktime");
        MIME_TYPES.put("webm", "video/webm");
    }

    @Override
    public void handle(Parameter request, OutputStream response) {
        PrintWriter writer = new PrintWriter(response);

        try {
            // 1. 获取请求路径并映射到文件系统路径
            String requestPath = request.getUrl();

            // 处理根路径，映射到 index.html
            if (requestPath.equals("/") || requestPath.isEmpty()) {
                requestPath = "/index.html";
            }

            // 移除开头的斜杠，构建相对路径
            String relativePath = requestPath.substring(1);

            // 2. 根据 Config.getWebRoot() 构建完整文件路径
            Path filePath = Paths.get(Config.getInstance().getWebRoot(), relativePath).normalize();
            Path webRootPath = Paths.get(Config.getInstance().getWebRoot()).normalize();

            // 安全检查：确保请求的文件在webroot目录内
            if (!filePath.startsWith(webRootPath)) {
                sendErrorResponse(writer, 403, "Forbidden - Access denied");
                return;
            }

            // 3. 检查文件是否存在且可读
            if (Files.exists(filePath) && Files.isRegularFile(filePath) && Files.isReadable(filePath)) {
                serveFile(filePath, request, response, writer);
            } else {
                // 文件不存在或不可访问
                sendErrorResponse(writer, 404, "Not Found - The requested resource was not found");
            }

        } catch (Exception e) {
            System.err.println("DefaultHandler处理异常: " + e.getMessage());
            sendErrorResponse(writer, 500, "Internal Server Error - " + e.getMessage());
        }
    }

    /**
     * 服务静态文件
     */
    private void serveFile(Path filePath, Parameter request, OutputStream response, PrintWriter writer) {
        try {
            // 读取文件内容
            byte[] fileBytes = Files.readAllBytes(filePath);

            // 获取文件信息
            String contentType = getContentType(filePath);
            long contentLength = Files.size(filePath);
            String lastModified = getLastModified(filePath);

            // 检查条件请求（If-Modified-Since）
            String ifModifiedSince = request.getHeader("If-Modified-Since");
            if (ifModifiedSince != null && ifModifiedSince.equals(lastModified)) {
                // 文件未修改，返回304 Not Modified
                writer.println("HTTP/1.1 304 Not Modified");
                writer.println("Server: MiniWebSvr/1.0");
                writer.println("Connection: close");
                writer.println();
                writer.flush();
                System.out.println("文件未修改，返回304: " + filePath);
                return;
            }

            // 写入响应头
            writer.println("HTTP/1.1 200 OK");
            writer.println("Content-Type: " + contentType);
            writer.println("Content-Length: " + contentLength);
            writer.println("Last-Modified: " + lastModified);
            writer.println("Connection: close");
            writer.println("Server: MiniWebSvr/1.0");
            writer.println("Cache-Control: public, max-age=3600"); // 缓存1小时

            // 对于文本文件，添加字符集信息
            if (contentType.startsWith("text/") || contentType.contains("javascript") || contentType.contains("json")) {
                if (!contentType.contains("charset")) {
                    writer.println("Content-Type: " + contentType + "; charset=UTF-8");
                }
            }

            writer.println(); // 空行分隔头部和正文
            writer.flush();

            // 写入文件内容
            response.write(fileBytes);
            response.flush();

            System.out.println("成功服务文件: " + filePath + " (" + contentLength + " bytes)");

        } catch (IOException e) {
            System.err.println("读取文件失败: " + filePath + " - " + e.getMessage());
            sendErrorResponse(writer, 500, "Internal Server Error - File read error");
        }
    }

    /**
     * 获取文件的MIME类型
     */
    private String getContentType(Path filePath) {
        try {
            String fileName = filePath.getFileName().toString().toLowerCase();
            int dotIndex = fileName.lastIndexOf('.');

            if (dotIndex > 0) {
                String extension = fileName.substring(dotIndex + 1);
                String mimeType = MIME_TYPES.get(extension);
                if (mimeType != null) {
                    return mimeType;
                }
            }

            // 如果映射中没有，使用系统探测
            String probedType = Files.probeContentType(filePath);
            return probedType != null ? probedType : "application/octet-stream";

        } catch (IOException e) {
            return "application/octet-stream";
        }
    }

    /**
     * 获取文件的最后修改时间（HTTP格式）
     */
    private String getLastModified(Path filePath) {
        try {
            return Files.getLastModifiedTime(filePath)
                    .toInstant()
                    .atZone(ZoneId.of("GMT"))
                    .format(DateTimeFormatter.RFC_1123_DATE_TIME);
        } catch (IOException e) {
            return ZonedDateTime.now(ZoneId.of("GMT"))
                    .format(DateTimeFormatter.RFC_1123_DATE_TIME);
        }
    }

    /**
     * 发送错误响应
     */
    private void sendErrorResponse(PrintWriter writer, int statusCode, String message) {
        try {
            String statusText = getStatusText(statusCode);
            String plainContent = statusCode + " " + statusText + "\n" + message;
            byte[] contentBytes = plainContent.getBytes("UTF-8");

            writer.println("HTTP/1.1 " + statusCode + " " + statusText);
            writer.println("Content-Type: text/plain; charset=UTF-8");
            writer.println("Content-Length: " + contentBytes.length);
            writer.println("Connection: close");
            writer.println("Server: MiniWebSvr/1.0");
            writer.println();
            writer.print(plainContent);
            writer.flush();

            System.out.println("发送错误响应: " + statusCode + " - " + message);

        } catch (Exception e) {
            System.err.println("发送错误响应失败: " + e.getMessage());
        }
    }

    /**
     * 获取HTTP状态码对应的文本描述
     */
    private String getStatusText(int statusCode) {
        switch (statusCode) {
            case 200: return "OK";
            case 304: return "Not Modified";
            case 400: return "Bad Request";
            case 403: return "Forbidden";
            case 404: return "Not Found";
            case 500: return "Internal Server Error";
            case 501: return "Not Implemented";
            default: return "Unknown Error";
        }
    }
}